#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>

/*
	mykeys{
		interrupt-parent = <&gpiof>;
		interrupts = <9 0>,<7 0>, <8 0>; 
		interrupts-name = "key1", "key2", "key3";
	};
 */

MODULE_LICENSE("GPL");

typedef struct{
    unsigned int m_irqNumber;
    const char* m_irqName;
}btn_desc_t;

static btn_desc_t btns[3];
static struct device_node* btnNode;

void btn_delayed_work_bottom_half_func(struct work_struct *work)
{
    printk("enter bottom half, do no urgency things...\n");
    msleep(1);
}
DECLARE_DELAYED_WORK(btnDelayedWork,btn_delayed_work_bottom_half_func);

irqreturn_t btn_irqHandler(int irq, void* dev)
{
    btn_desc_t* data = (btn_desc_t*)dev;
    printk("enter top half, do urgency things...\n");
    printk("%s is pressed!\n", data->m_irqName);
    printk("register bottom half\n");
    schedule_delayed_work(&btnDelayedWork, 10*HZ);
    printk("exit from top half\n");
    return IRQ_HANDLED;
}

static int __init btn_drv_init(void)
{
    int i=0,ret;
    btnNode = of_find_node_by_path("/mykeys");

    for(;i<ARRAY_SIZE(btns);i++)
    {
        btns[i].m_irqNumber = irq_of_parse_and_map(btnNode,i);
        of_property_read_string_index(btnNode,"interrupts-name",i,&btns[i].m_irqName);
        ret = request_irq(btns[i].m_irqNumber,btn_irqHandler,IRQF_TRIGGER_FALLING,btns[i].m_irqName,&btns[i]);
        if(ret < 0)
        {
            printk("request_irq is failed by %s\n",btns[i].m_irqName);
            return ret;
        }
    }
    return 0;
}

static void __exit btn_drv_exit(void)
{
    int i = 0;
    flush_delayed_work(&btnDelayedWork);
    for(;i<ARRAY_SIZE(btns);i++)
    {
        free_irq(btns[i].m_irqNumber,&btns[i]);
    }
}

module_init(btn_drv_init);
module_exit(btn_drv_exit);